home *** CD-ROM | disk | FTP | other *** search
/ Aminet 44 / Aminet 44 (2001)(GTI - Schatztruhe)[!][Aug 2001].iso / Aminet / dev / debug / Sashimi.lha / source / sashimi.c < prev    next >
C/C++ Source or Header  |  2001-06-26  |  32KB  |  1,346 lines

  1. /*
  2.  * $Id: sashimi.c 1.10 2001/06/26 12:37:51 olsen Exp olsen $
  3.  *
  4.  * Sashimi -- intercepts raw serial debugging output on your own machine
  5.  *
  6.  * Written by Olaf `Olsen' Barthel <olsen@sourcery.han.de>
  7.  * Public Domain
  8.  *
  9.  * :ts=4
  10.  */
  11.  
  12. /****************************************************************************/
  13.  
  14. #define NULL ((APTR)0UL)
  15.  
  16. /****************************************************************************/
  17.  
  18. #include <exec/execbase.h>
  19. #include <exec/memory.h>
  20.  
  21. #include <devices/timer.h>
  22.  
  23. #include <dos/dosextens.h>
  24. #include <dos/rdargs.h>
  25.  
  26. #include <clib/timer_protos.h>
  27. #include <clib/exec_protos.h>
  28. #include <clib/dos_protos.h>
  29.  
  30. #include <pragmas/timer_pragmas.h>
  31. #include <pragmas/exec_sysbase_pragmas.h>
  32. #include <pragmas/dos_pragmas.h>
  33.  
  34. #define USE_BUILTIN_MATH
  35. #include <string.h>
  36. #include <stddef.h>
  37. #include <stdio.h>
  38.  
  39. /****************************************************************************/
  40.  
  41. STRPTR Version = "$VER: Sashimi 1.7 (26.6.2001)\r\n";
  42.  
  43. /****************************************************************************/
  44.  
  45. #define OK        (0)
  46. #define NOT        !
  47. #define BUSY    NULL
  48. #define ZERO    ((BPTR)0UL)
  49.  
  50. /****************************************************************************/
  51.  
  52. enum
  53. {
  54.     MODE_Regular,
  55.     MODE_Recovery
  56. };
  57.  
  58. /****************************************************************************/
  59.  
  60. #define MILLION 1000000
  61.  
  62. /****************************************************************************/
  63.  
  64. STATIC struct Device * TimerBase;
  65.  
  66. /****************************************************************************/
  67.  
  68. extern struct Library * SysBase;
  69. extern struct Library * DOSBase;
  70.  
  71. /****************************************************************************/
  72.  
  73. typedef LONG    SWITCH;
  74. typedef LONG *    NUMBER;
  75. typedef STRPTR    KEY;
  76.  
  77. STATIC struct
  78. {
  79.     /* Startup options */
  80.     KEY        Recover;    /* Recover any old Sashimi buffer still in memory */
  81.     SWITCH    On;            /* Ignored */
  82.     NUMBER    BufferK;    /* Buffer size, to the power of two */
  83.     NUMBER    BufferSize;    /* Buffer size in bytes */
  84.     SWITCH    NoPrompt;    /* Do not show the initial prompt message */
  85.     SWITCH    Quiet;        /* Do not produce any output at all */
  86.     SWITCH    AskExit;    /* Ask whether to exit the program */
  87.     SWITCH    AskSave;    /* Ask for a file to save the buffer to when exiting */
  88.     SWITCH    TimerOn;    /* Check the circular buffer every 1/10 of a second */
  89.     SWITCH    Console;    /* Open a console window for I/O */
  90.     KEY        Window;        /* Console window specifier */
  91.  
  92.     /* Runtime options */
  93.     SWITCH    Off;        /* Turn Sashimi off */
  94.     SWITCH    Save;        /* Save the circular buffer contents */
  95.     KEY        SaveAs;        /* Save the circular buffer contents under a specific name */
  96.     SWITCH    Empty;        /* Empty the circular buffer */
  97.     SWITCH    Wake;        /* Wake up Sashimi, push it out of Quiet mode */
  98. } ShellArguments;
  99.  
  100. STATIC const STRPTR ShellTemplate =
  101.     "RECOVER/K,"
  102.     "ON/S,"
  103.     "BUFK/N,"
  104.     "BUFFERSIZE/N,"
  105.     "NOPROMPT/S,"
  106.     "QUIET/S,"
  107.     "ASKEXIT/S,"
  108.     "ASKSAVE/S,"
  109.     "TIMERON/S,"
  110.     "CONSOLE/S,"
  111.     "WINDOW/K,"
  112.     "OFF/S,"
  113.     "SAVE/S,"
  114.     "SAVEAS/K,"
  115.     "EMPTY/S,"
  116.     "WAKE/S";
  117.  
  118. /****************************************************************************/
  119.  
  120. /* Eat me */
  121. #define COOKIE 0x26062001
  122.  
  123. struct SashimiResource
  124. {
  125.     struct Library    sr_Library;            /* Global link */
  126.     UWORD            sr_Pad;                /* Long word alignment */
  127.  
  128.     ULONG            sr_Cookie;            /* Magic marker */
  129.     APTR            sr_PointsToCookie;    /* Points back to cookie */
  130.     ULONG            sr_CreatedWhen;        /* When exactly was this data structure created? */
  131.  
  132.     struct Task *    sr_Owner;            /* Current owner of the patches */
  133.     LONG            sr_OwnerSigBit;
  134.     ULONG            sr_OwnerSigMask;    /* Signal mask to send when a new line is in the buffer. */
  135.  
  136.     LONG            sr_WakeSigBit;
  137.     ULONG            sr_WakeSigMask;        /* Signal mask to send to wake Sashimi up. */
  138.  
  139.     ULONG            sr_FIFOTotalSize;    /* Number of bytes allocated for the buffer */
  140.     ULONG            sr_FIFOReadIndex;    /* Read index counter */
  141.     ULONG            sr_FIFOWriteIndex;    /* Write index counter */
  142.     ULONG            sr_FIFOBytesStored;    /* Number of bytes in the FIFO */
  143.     BOOL            sr_FIFOOverrun;        /* TRUE if the write index counter has
  144.                                          * overrun the read index counter.
  145.                                          */
  146.     BOOL            sr_FIFOWrapped;        /* TRUE if the write index counter has
  147.                                          * wrapped around the circular buffer.
  148.                                          */
  149.     UBYTE            sr_FIFO[1];            /* The message buffer */
  150. };
  151.  
  152. STATIC const STRPTR SashimiResourceName = "sashimi.resource";
  153. STATIC struct SashimiResource * GlobalSashimiResource;
  154.  
  155. /****************************************************************************/
  156.  
  157. extern LONG __far LVORawIOInit;
  158. extern LONG __far LVORawMayGetChar;
  159. extern LONG __far LVORawPutChar;
  160.  
  161. /****************************************************************************/
  162.  
  163. STATIC APTR OldRawIOInit;
  164. STATIC APTR OldRawMayGetChar;
  165. STATIC APTR OldRawPutChar;
  166.  
  167. /****************************************************************************/
  168.  
  169. VOID __saveds __asm
  170. NewRawIOInit(VOID)
  171. {
  172.     /* Nothing happens here */
  173. }
  174.  
  175. LONG __saveds __asm
  176. NewRawMayGetChar(VOID)
  177. {
  178.     /* We always return sort of a confirmation. */
  179.     return('y');
  180. }
  181.  
  182. /****************************************************************************/
  183.  
  184. STATIC LONG
  185. GetCharsInFIFO(struct SashimiResource * sr)
  186. {
  187.     LONG result;
  188.  
  189.     Disable();
  190.  
  191.     if(sr->sr_FIFOWrapped)
  192.         result = sr->sr_FIFOTotalSize;
  193.     else
  194.         result = sr->sr_FIFOWriteIndex;
  195.  
  196.     Enable();
  197.  
  198.     return(result);
  199. }
  200.  
  201. STATIC VOID
  202. EmptyFIFO(struct SashimiResource * sr)
  203. {
  204.     Disable();
  205.  
  206.     sr->sr_FIFOReadIndex    = 0;
  207.     sr->sr_FIFOWriteIndex    = 0;
  208.     sr->sr_FIFOBytesStored    = 0;
  209.     sr->sr_FIFOOverrun        = FALSE;
  210.     sr->sr_FIFOWrapped        = FALSE;
  211.  
  212.     Enable();
  213. }
  214.  
  215. STATIC LONG
  216. ReadFIFOChars(struct SashimiResource * sr,UBYTE * buffer,LONG maxChars)
  217. {
  218.     LONG result = 0;
  219.  
  220.     Disable();
  221.  
  222.     if(sr->sr_FIFOBytesStored > 0)
  223.     {
  224.         LONG howMany;
  225.  
  226.         if(maxChars > sr->sr_FIFOBytesStored)
  227.             maxChars = sr->sr_FIFOBytesStored;
  228.  
  229.         do
  230.         {
  231.             /* Find out how many characters can be read
  232.              * from the FIFO without overrunning the
  233.              * end of it. We don't read more than these
  234.              * few characters in one go.
  235.              */
  236.             howMany = min(maxChars,sr->sr_FIFOTotalSize - sr->sr_FIFOReadIndex);
  237.  
  238.             memcpy(buffer,&sr->sr_FIFO[sr->sr_FIFOReadIndex],howMany);
  239.  
  240.             result        += howMany;
  241.             buffer        += howMany;
  242.             maxChars    -= howMany;
  243.  
  244.             sr->sr_FIFOReadIndex = (sr->sr_FIFOReadIndex + howMany) % sr->sr_FIFOTotalSize;
  245.         }
  246.         while(maxChars > 0);
  247.  
  248.         /* Subtract the number of characters we
  249.          * read in the loop.
  250.          */
  251.         sr->sr_FIFOBytesStored -= result;
  252.     }
  253.  
  254.     Enable();
  255.  
  256.     return(result);
  257. }
  258.  
  259. STATIC VOID
  260. StoreFIFOChar(struct SashimiResource * sr,UBYTE c)
  261. {
  262.     sr->sr_FIFO[sr->sr_FIFOWriteIndex] = c;
  263.     sr->sr_FIFOWriteIndex = (sr->sr_FIFOWriteIndex + 1) % sr->sr_FIFOTotalSize;
  264.  
  265.     /* If the buffer wraps around, remember it. */
  266.     if(sr->sr_FIFOWriteIndex == 0)
  267.         sr->sr_FIFOWrapped = TRUE;
  268.  
  269.     /* Check if the circular buffer was overrun */
  270.     sr->sr_FIFOBytesStored++;
  271.     if(sr->sr_FIFOBytesStored > sr->sr_FIFOTotalSize)
  272.     {
  273.         sr->sr_FIFOOverrun = TRUE;
  274.  
  275.         /* Move the read index to the same position as
  276.          * the write index and retain only as many
  277.          * bytes as would fit into the FIFO.
  278.          */
  279.         sr->sr_FIFOReadIndex = sr->sr_FIFOWriteIndex;
  280.         sr->sr_FIFOBytesStored = sr->sr_FIFOTotalSize;
  281.     }
  282. }
  283.  
  284. /****************************************************************************/
  285.  
  286. VOID __saveds __asm
  287. NewRawPutChar(register __d0 UBYTE c)
  288. {
  289.     /* Do not store NUL bytes. */
  290.     if(c != '\0')
  291.     {
  292.         STATIC ULONG Position = 0;
  293.  
  294.         Disable();
  295.  
  296.         /* Filter out extra <cr> characters. */
  297.         if(c != '\r' || Position > 0)
  298.         {
  299.             struct SashimiResource * sr = GlobalSashimiResource;
  300.  
  301.             /* Store another byte in the buffer */
  302.             StoreFIFOChar(sr,c);
  303.  
  304.             /* Notify Sashimi every time there is an end of line
  305.              * character in the stream.
  306.              */
  307.             if(c == '\n' || c == '\r')
  308.                 Signal(sr->sr_Owner,sr->sr_OwnerSigMask);
  309.         }
  310.  
  311.         if(c == '\r' || c == '\n')
  312.             Position = 0;
  313.         else
  314.             Position++;
  315.  
  316.         Enable();
  317.     }
  318. }
  319.  
  320. /****************************************************************************/
  321.  
  322. /* This is in SafeRawPutChar.asm */
  323. extern VOID __asm SafeRawPutChar(register __d0 UBYTE c);
  324.  
  325. STATIC VOID
  326. RemovePatches(VOID)
  327. {
  328.     APTR res;
  329.  
  330.     /* We disable the interrupts because the raw I/O routines can
  331.      * be called from within interrupt code.
  332.      */
  333.     Disable();
  334.  
  335.     /* For every patch planted, remove it and check whether the code
  336.      * had been patched before. If it has, restore the patch. Note that
  337.      * this is not bullet proof :(
  338.      */
  339.     res = SetFunction(SysBase,(LONG)&LVORawIOInit,(ULONG (*)())OldRawIOInit);
  340.     if(res != (APTR)NewRawIOInit)
  341.         SetFunction(SysBase,(LONG)&LVORawIOInit,(ULONG (*)())res);
  342.  
  343.     res = SetFunction(SysBase,(LONG)&LVORawMayGetChar,(ULONG (*)())OldRawMayGetChar);
  344.     if(res != (APTR)NewRawMayGetChar)
  345.         SetFunction(SysBase,(LONG)&LVORawMayGetChar,(ULONG (*)())res);
  346.  
  347.     res = SetFunction(SysBase,(LONG)&LVORawPutChar,(ULONG (*)())OldRawPutChar);
  348.     if(res != (APTR)SafeRawPutChar)
  349.         SetFunction(SysBase,(LONG)&LVORawPutChar,(ULONG (*)())res);
  350.  
  351.     Enable();
  352. }
  353.  
  354. STATIC VOID
  355. InstallPatches(VOID)
  356. {
  357.     /* We disable the interrupts because the raw I/O routines can
  358.      * be called from within interrupt code.
  359.      */
  360.     Disable();
  361.  
  362.     OldRawIOInit        = SetFunction(SysBase,(LONG)&LVORawIOInit,        (ULONG (*)())NewRawIOInit);
  363.     OldRawMayGetChar    = SetFunction(SysBase,(LONG)&LVORawMayGetChar,    (ULONG (*)())NewRawMayGetChar);
  364.     OldRawPutChar        = SetFunction(SysBase,(LONG)&LVORawPutChar,        (ULONG (*)())SafeRawPutChar);
  365.  
  366.     Enable();
  367. }
  368.  
  369. /****************************************************************************/
  370.  
  371. STATIC VOID
  372. FreeSashimiResource(struct SashimiResource * sr)
  373. {
  374.     if(sr != NULL)
  375.     {
  376.         FreeSignal(sr->sr_OwnerSigBit);
  377.         FreeSignal(sr->sr_WakeSigBit);
  378.  
  379.         /* Destroy the markers */
  380.         sr->sr_Cookie            = 0;
  381.         sr->sr_PointsToCookie    = NULL;
  382.  
  383.         FreeMem(sr,sizeof(*sr) + sr->sr_FIFOTotalSize-1);
  384.     }
  385. }
  386.  
  387. STATIC LONG
  388. RemoveSashimiResource(struct SashimiResource * sr)
  389. {
  390.     LONG error = OK;
  391.  
  392.     if(sr != NULL)
  393.     {
  394.         Forbid();
  395.  
  396.         /* Allow the resource to be removed only if
  397.          * there are no customers using it.
  398.          */
  399.         if(sr->sr_Library.lib_OpenCnt == 0)
  400.             RemResource(sr);
  401.         else
  402.             error = ERROR_OBJECT_IN_USE;
  403.  
  404.         Permit();
  405.     }
  406.  
  407.     return(error);
  408. }
  409.  
  410. STATIC LONG
  411. AddSashimiResource(ULONG bufferSize,struct SashimiResource ** resourcePtr)
  412. {
  413.     struct SashimiResource * sr;
  414.     LONG error = OK;
  415.  
  416.     /* We will do something really tricky; to increase our chances of
  417.      * allocating an old Sashimi buffer to be recovered, we allocate
  418.      * the amount of memory needed plus the size of a memory chunk.
  419.      * Then we release that buffer again and reallocate it with the
  420.      * size of the memory chunk trailing behind it.
  421.      */
  422.  
  423.     Forbid();
  424.  
  425.     sr = AllocMem(sizeof(struct MemChunk) + sizeof(*sr) + bufferSize-1,MEMF_ANY|MEMF_PUBLIC);
  426.     if(sr != NULL)
  427.     {
  428.         FreeMem(sr,sizeof(struct MemChunk) + sizeof(*sr) + bufferSize-1);
  429.         sr = AllocAbs(sizeof(*sr) + bufferSize-1,(BYTE *)sr + sizeof(struct MemChunk));
  430.     }
  431.  
  432.     Permit();
  433.  
  434.     if(sr != NULL)
  435.     {
  436.         struct timeval now;
  437.  
  438.         GetSysTime(&now);
  439.  
  440.         memset(sr,0,sizeof(*sr)-1);
  441.  
  442.         sr->sr_Library.lib_Node.ln_Name    = (char *)SashimiResourceName;
  443.         sr->sr_Library.lib_Node.ln_Type    = NT_RESOURCE;
  444.         sr->sr_Owner                    = FindTask(NULL);
  445.         sr->sr_FIFOTotalSize            = bufferSize;
  446.         sr->sr_Cookie                    = COOKIE;
  447.         sr->sr_PointsToCookie            = &sr->sr_Cookie;
  448.         sr->sr_CreatedWhen                = now.tv_secs;
  449.         sr->sr_WakeSigBit                = -1;
  450.  
  451.         sr->sr_OwnerSigBit = AllocSignal(-1);
  452.         if(sr->sr_OwnerSigBit != -1)
  453.         {
  454.             sr->sr_OwnerSigMask = (1UL << sr->sr_OwnerSigBit);
  455.  
  456.             sr->sr_WakeSigBit = AllocSignal(-1);
  457.             if(sr->sr_WakeSigBit != -1)
  458.             {
  459.                 sr->sr_WakeSigMask = (1UL << sr->sr_WakeSigBit);
  460.  
  461.                 Forbid();
  462.  
  463.                 /* Do not add the resource if it has already been installed. */
  464.                 if(OpenResource((STRPTR)SashimiResourceName) == NULL)
  465.                     AddResource(sr);
  466.                 else
  467.                     error = ERROR_OBJECT_EXISTS;
  468.  
  469.                 Permit();
  470.             }
  471.             else
  472.             {
  473.                 error = ERROR_NO_FREE_STORE;
  474.             }
  475.         }
  476.         else
  477.         {
  478.             error = ERROR_NO_FREE_STORE;
  479.         }
  480.     }
  481.     else
  482.     {
  483.         error = ERROR_NO_FREE_STORE;
  484.     }
  485.  
  486.     if(error != OK)
  487.     {
  488.         FreeSashimiResource(sr);
  489.         sr = NULL;
  490.     }
  491.  
  492.     (*resourcePtr) = sr;
  493.  
  494.     return(error);
  495. }
  496.  
  497. /****************************************************************************/
  498.  
  499. STATIC VOID
  500. CloseSashimiResource(struct SashimiResource * sr)
  501. {
  502.     if(sr != NULL)
  503.     {
  504.         Forbid();
  505.  
  506.         sr->sr_Library.lib_OpenCnt--;
  507.  
  508.         Permit();
  509.     }
  510. }
  511.  
  512. STATIC struct SashimiResource *
  513. OpenSashimiResource(VOID)
  514. {
  515.     struct SashimiResource * sr;
  516.  
  517.     Forbid();
  518.  
  519.     sr = OpenResource((STRPTR)SashimiResourceName);
  520.     if(sr != NULL)
  521.         sr->sr_Library.lib_OpenCnt++;
  522.  
  523.     Permit();
  524.  
  525.     return(sr);
  526. }
  527.  
  528. /****************************************************************************/
  529.  
  530. STATIC LONG
  531. SaveBuffer(const STRPTR name,struct SashimiResource * sr,LONG mode)
  532. {
  533.     LONG error = OK;
  534.     STRPTR buffer;
  535.  
  536.     /* We allocate a temporary buffer to store the circular
  537.      * buffer data in.
  538.      */
  539.     buffer = AllocVec(sr->sr_FIFOTotalSize,MEMF_ANY|MEMF_PUBLIC);
  540.     if(buffer != NULL)
  541.     {
  542.         LONG bytesInBuffer;
  543.         BOOL wrapped;
  544.         BOOL overrun;
  545.         BPTR file;
  546.  
  547.         if(mode == MODE_Regular)
  548.         {
  549.             /* Stop interrupts and multitasking for a tick. */
  550.             Disable();
  551.         }
  552.  
  553.         wrapped = sr->sr_FIFOWrapped;
  554.         overrun = sr->sr_FIFOOverrun;
  555.  
  556.         if(wrapped)
  557.         {
  558.             LONG oldBytes = sr->sr_FIFOTotalSize - sr->sr_FIFOWriteIndex;
  559.  
  560.             /* Unwrap the buffer; first copy the old data (following the
  561.              * write index) then the newer data.
  562.              */
  563.             memcpy(buffer,&sr->sr_FIFO[sr->sr_FIFOWriteIndex],oldBytes);
  564.             memcpy(&buffer[oldBytes],sr->sr_FIFO,sr->sr_FIFOWriteIndex);
  565.  
  566.             bytesInBuffer = sr->sr_FIFOTotalSize;
  567.         }
  568.         else
  569.         {
  570.             memcpy(buffer,sr->sr_FIFO,sr->sr_FIFOWriteIndex);
  571.  
  572.             bytesInBuffer = sr->sr_FIFOWriteIndex;
  573.         }
  574.  
  575.         if(mode == MODE_Regular)
  576.         {
  577.             /* Start interrupts and multitasking again. */
  578.             Enable();
  579.         }
  580.  
  581.         /* Write the buffer contents. */
  582.         file = Open((STRPTR)name,MODE_NEWFILE);
  583.         if(file != ZERO)
  584.         {
  585.             if(mode == MODE_Recovery)
  586.             {
  587.                 if(FPrintf(file,"RECOVERY WARNING - Data may have been damaged\n") < 0)
  588.                     error = IoErr();
  589.             }
  590.  
  591.             if(error == OK && overrun)
  592.             {
  593.                 if(FPrintf(file,"BUFFER WAS OVERRUN - Data may have been lost\n") < 0)
  594.                     error = IoErr();
  595.             }
  596.  
  597.             if(error == OK && wrapped)
  598.             {
  599.                 if(FPrintf(file,"BUFFER WRAPPED - This is the most recent captured data\n\n") < 0)
  600.                     error = IoErr();
  601.             }
  602.  
  603.             /* FPrintf() is a buffered I/O routine, this is why we need to flush the
  604.              * output buffer here. Otherwise, it would be flushed after the Write()
  605.              * command below is finished and the file is closed. This is not what
  606.              * we want as that would have the effect of adding the messages above
  607.              * to the end of the file.
  608.              */
  609.             if(error == OK)
  610.                 Flush(file);
  611.  
  612.             if(error == OK)
  613.             {
  614.                 if(Write(file,buffer,bytesInBuffer) != bytesInBuffer)
  615.                     error = IoErr();
  616.             }
  617.  
  618.             Close(file);
  619.         }
  620.         else
  621.         {
  622.             error = IoErr();
  623.         }
  624.  
  625.         FreeVec(buffer);
  626.     }
  627.     else
  628.     {
  629.         error = ERROR_NO_FREE_STORE;
  630.     }
  631.  
  632.     return(error);
  633. }
  634.  
  635. /****************************************************************************/
  636.  
  637. STATIC BOOL
  638. Recover(const STRPTR fileName)
  639. {
  640.     struct SashimiResource * sr = NULL;
  641.     APTR allocated = NULL;
  642.     struct MemHeader * mh;
  643.     ULONG * start;
  644.     ULONG * end;
  645.     BOOL success;
  646.  
  647.     Printf("Trying to recover old Sashimi buffer... ");
  648.     Flush(Output());
  649.  
  650.     Forbid();
  651.  
  652.     /* Scan the system memory list. */
  653.     for(mh = (struct MemHeader *)((struct ExecBase *)SysBase)->MemList.lh_Head ;
  654.         mh->mh_Node.ln_Succ != NULL ;
  655.         mh = (struct MemHeader *)mh->mh_Node.ln_Succ)
  656.     {
  657.         start    = (ULONG *)mh->mh_Lower;
  658.         end        = (ULONG *)mh->mh_Upper;
  659.  
  660.         do
  661.         {
  662.             /* First look for the cookie... */
  663.             if(start[0] == COOKIE)
  664.             {
  665.                 /* Then look for the pointer back to it. */
  666.                 if(start[1] == (ULONG)start)
  667.                 {
  668.                     /* Unless we don't have a resource pointer
  669.                      * yet, compare the creation times and take
  670.                      * only the latest buffer.
  671.                      */
  672.                     if(sr == NULL || start[2] > sr->sr_CreatedWhen)
  673.                         sr = (struct SashimiResource *)((ULONG)start - offsetof(struct SashimiResource,sr_Cookie));
  674.                 }
  675.             }
  676.         }
  677.         while(++start != end);
  678.     }
  679.  
  680.     /* Try to allocate the memory the old buffer occupies. */
  681.     if(sr != NULL)
  682.         allocated = AllocAbs(sizeof(*sr) + sr->sr_FIFOTotalSize-1 + sizeof(struct MemChunk),(BYTE *)sr - sizeof(struct MemChunk));
  683.  
  684.     Permit();
  685.  
  686.     if(sr != NULL)
  687.     {
  688.         LONG error = OK;
  689.         LONG numBytes;
  690.  
  691.         if(sr->sr_FIFOWrapped)
  692.             numBytes = sr->sr_FIFOTotalSize;
  693.         else
  694.             numBytes = sr->sr_FIFOWriteIndex;
  695.  
  696.         Printf("found something (%ld bytes).\n",numBytes);
  697.  
  698.         /* If there is anything worth saving, save it. */
  699.         if(numBytes > 0)
  700.         {
  701.             error = SaveBuffer(fileName,sr,MODE_Recovery);
  702.             if(error == OK)
  703.                 Printf("Recovered Sashimi buffer saved as \"%s\".\n",fileName);
  704.             else
  705.                 PrintFault(error,fileName);
  706.         }
  707.         else
  708.         {
  709.             Printf("This is not worth saving.\n");
  710.         }
  711.  
  712.         /* If everything went fine so far and
  713.          * if we are the owner of the buffer,
  714.          * mark it as invalid.
  715.          */
  716.         if(error == OK && allocated != NULL)
  717.         {
  718.             sr->sr_Cookie            = 0;
  719.             sr->sr_PointsToCookie    = NULL;
  720.         }
  721.  
  722.         success = TRUE;
  723.     }
  724.     else
  725.     {
  726.         Printf("sorry.\n");
  727.  
  728.         success = FALSE;
  729.     }
  730.  
  731.     /* Release the buffer... */
  732.     if(allocated != NULL)
  733.         FreeMem(allocated,sizeof(*sr) + sr->sr_FIFOTotalSize-1 + sizeof(struct MemChunk));
  734.  
  735.     return(success);
  736. }
  737.  
  738. /****************************************************************************/
  739.  
  740. int
  741. main(int argc,char **argv)
  742. {
  743.     int result = RETURN_FAIL;
  744.  
  745.     /* Kickstart 2.04 and a Shell window are required. */
  746.     if(DOSBase->lib_Version >= 37 && argc > 0)
  747.     {
  748.         struct RDArgs * rdargs;
  749.  
  750.         rdargs = ReadArgs((STRPTR)ShellTemplate,(LONG *)&ShellArguments,NULL);
  751.         if(rdargs != NULL)
  752.         {
  753.             /* Before anything else happens, check if
  754.              * we should recover any old data.
  755.              */
  756.             if(ShellArguments.Recover != NULL)
  757.             {
  758.                 if(Recover(ShellArguments.Recover))
  759.                     result = RETURN_OK;
  760.                 else
  761.                     result = RETURN_WARN;
  762.             }
  763.             else
  764.             {
  765.                 struct SashimiResource * sr = NULL;
  766.                 struct MsgPort * timePort;
  767.                 struct timerequest * timeRequest = NULL;
  768.                 BOOL added = FALSE;
  769.                 BOOL opened = FALSE;
  770.                 LONG error = OK;
  771.                 BPTR oldOutput = ZERO;
  772.                 BPTR newOutput = ZERO;
  773.                 BPTR oldInput = ZERO;
  774.                 BPTR newInput = ZERO;
  775.                 struct MsgPort * oldConsoleTask = NULL;
  776.                 STRPTR saveFile;
  777.  
  778.                 /* Fill in the save file name, we might need it later. */
  779.                 if(ShellArguments.SaveAs != NULL)
  780.                     saveFile = ShellArguments.SaveAs;
  781.                 else
  782.                     saveFile = "T:sashimi.out";
  783.  
  784.                 /* Set up the timer.device interface. */
  785.                 timePort = CreateMsgPort();
  786.                 if(timePort != NULL)
  787.                 {
  788.                     timeRequest = (struct timerequest *)CreateIORequest(timePort,sizeof(*timeRequest));
  789.                     if(timeRequest != NULL)
  790.                     {
  791.                         if(OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)timeRequest,0) == OK)
  792.                             TimerBase = timeRequest->tr_node.io_Device;
  793.                         else
  794.                             error = ERROR_NO_FREE_STORE; /* Misleading? */
  795.                     }
  796.                     else
  797.                     {
  798.                         error = ERROR_NO_FREE_STORE;
  799.                     }
  800.                 }
  801.                 else
  802.                 {
  803.                     error = ERROR_NO_FREE_STORE;
  804.                 }
  805.  
  806.                 if(error == OK)
  807.                 {
  808.                     /* Try to open the resource, and if that fails, create one. */
  809.                     sr = OpenSashimiResource();
  810.                     if(sr != NULL)
  811.                     {
  812.                         opened = TRUE;
  813.                     }
  814.                     else
  815.                     {
  816.                         ULONG bufferSize;
  817.     
  818.                         /* The default buffer size is 32K. */
  819.                         bufferSize = 32 * 1024;
  820.     
  821.                         /* Check for a specific buffer size (power of two). */
  822.                         if(ShellArguments.BufferK != NULL)
  823.                             bufferSize = 1024 * (*ShellArguments.BufferK);
  824.     
  825.                         /* Check for a specific buffer size. */
  826.                         if(ShellArguments.BufferSize != NULL)
  827.                             bufferSize = (ULONG)(*ShellArguments.BufferSize);
  828.     
  829.                         /* Don't make the buffer too small. */
  830.                         if(bufferSize < 4096)
  831.                             bufferSize = 4096;
  832.     
  833.                         /* Add the resource to the public list. Note that
  834.                          * the patches are not installed yet.
  835.                          */
  836.                         error = AddSashimiResource(bufferSize,&sr);
  837.                         if(error == OK)
  838.                             added = TRUE;
  839.                     }
  840.                 }
  841.  
  842.                 /* Did we get everything we wanted? */
  843.                 if(error != OK)
  844.                 {
  845.                     PrintFault(error,"Sashimi");
  846.                     result = RETURN_ERROR;
  847.                 }
  848.                 else
  849.                 {
  850.                     if(opened)
  851.                     {
  852.                         /* Save the current circular buffer contents? */
  853.                         if(ShellArguments.SaveAs != NULL || ShellArguments.Save)
  854.                         {
  855.                             LONG error;
  856.  
  857.                             error = SaveBuffer(saveFile,sr,MODE_Regular);
  858.                             if(error == OK)
  859.                                 Printf("Sashimi buffer saved as \"%s\".\n",saveFile);
  860.                             else
  861.                                 PrintFault(error,saveFile);
  862.                         }
  863.  
  864.                         /* Empty the circular buffer? */
  865.                         if(ShellArguments.Empty)
  866.                         {
  867.                             EmptyFIFO(sr);
  868.  
  869.                             Printf("Sashimi buffer cleared.\n");
  870.                         }
  871.  
  872.                         /* Turn off Sashimi? */
  873.                         if(ShellArguments.Off)
  874.                         {
  875.                             struct Task * owner;
  876.  
  877.                             Forbid();
  878.  
  879.                             /* We cannot tell Sashimi to quit
  880.                              * if there is a single customer
  881.                              * left, such as us. This is why
  882.                              * we close the resource and
  883.                              * signal Sashimi to quit.
  884.                              */
  885.                             owner = sr->sr_Owner;
  886.                             CloseSashimiResource(sr);
  887.                             sr = NULL;
  888.  
  889.                             Signal(owner,SIGBREAKF_CTRL_C);
  890.  
  891.                             Permit();
  892.                         }
  893.  
  894.                         /* Wake up Sashimi */
  895.                         if(ShellArguments.Wake)
  896.                         {
  897.                             Signal(sr->sr_Owner,sr->sr_WakeSigMask);
  898.  
  899.                             Printf("Woke up Sashimi.\n");
  900.                         }
  901.                     }
  902.  
  903.                     if(added && NOT ShellArguments.Off)
  904.                     {
  905.                         ULONG signalsReceived,signalsToWaitFor;
  906.                         BOOL done;
  907.  
  908.                         /* Open a console window? */
  909.                         if(ShellArguments.Console)
  910.                         {
  911.                             STRPTR consoleWindow;
  912.                             LONG error = OK;
  913.  
  914.                             if(ShellArguments.Window != NULL)
  915.                                 consoleWindow = ShellArguments.Window;
  916.                             else
  917.                                 consoleWindow = "CON:0/20/640/100/Sashimi  [Ctrl]+E=Empty  [Ctrl]+F=File  [Ctrl]+D=Reset console/AUTO/CLOSE/WAIT/INACTIVE";
  918.  
  919.                             /* Open the window and make it the default
  920.                              * I/O stream.
  921.                              */
  922.                             newInput = Open(consoleWindow,MODE_NEWFILE);
  923.                             if(newInput != ZERO)
  924.                             {
  925.                                 oldConsoleTask = SetConsoleTask(((struct FileHandle *)BADDR(newInput))->fh_Type);
  926.                                 newOutput = Open("CONSOLE:",MODE_OLDFILE);
  927.                                 if(newOutput != ZERO)
  928.                                 {
  929.                                     oldInput = SelectInput(newInput);
  930.                                     oldOutput = SelectOutput(newOutput);
  931.                                 }
  932.                                 else
  933.                                 {
  934.                                     error = IoErr();
  935.  
  936.                                     /* Return to the original console task. */
  937.                                     SetConsoleTask(oldConsoleTask);
  938.                                     oldConsoleTask = NULL;
  939.                                 }
  940.                             }
  941.                             else
  942.                             {
  943.                                 error = IoErr();
  944.                             }
  945.  
  946.                             if(error != OK)
  947.                                 PrintFault(error,consoleWindow);
  948.                         }
  949.  
  950.                         /* Show the banner message. */
  951.                         if(NOT ShellArguments.NoPrompt && NOT ShellArguments.Quiet)
  952.                         {
  953.                             struct Process * cli = (struct Process *)FindTask(NULL);
  954.                             LONG maxCli,thisCli = 1,i;
  955.  
  956.                             /* Find our current CLI process number. */
  957.                             maxCli = MaxCli();
  958.                             for(i = 1 ; i <= maxCli ; i++)
  959.                             {
  960.                                 if(FindCliProc(i) == cli)
  961.                                 {
  962.                                     thisCli = i;
  963.                                     break;
  964.                                 }
  965.                             }
  966.  
  967.                             Printf("Sashimi installed ([Ctrl]+C or \"Break %ld\" to remove)\n",thisCli);
  968.                         }
  969.  
  970.                         GlobalSashimiResource = sr;
  971.                         InstallPatches();
  972.  
  973.                         signalsToWaitFor = SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D |
  974.                                            SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F |
  975.                                            sr->sr_OwnerSigMask |
  976.                                            sr->sr_WakeSigMask;
  977.  
  978.                         /* Start the timer. */
  979.                         if(ShellArguments.TimerOn)
  980.                         {
  981.                             signalsToWaitFor |= (1UL << timePort->mp_SigBit);
  982.  
  983.                             timeRequest->tr_node.io_Command    = TR_ADDREQUEST;
  984.                             timeRequest->tr_time.tv_secs    = 0;
  985.                             timeRequest->tr_time.tv_micro    = MILLION / 10;
  986.  
  987.                             SendIO((struct IORequest *)timeRequest);
  988.                         }
  989.  
  990.                         done = FALSE;
  991.                         do
  992.                         {
  993.                             signalsReceived = Wait(signalsToWaitFor);
  994.  
  995.                             /* Check if we should test the buffer. */
  996.                             if(ShellArguments.TimerOn)
  997.                             {
  998.                                 if(signalsReceived & (1UL << timePort->mp_SigBit))
  999.                                 {
  1000.                                     signalsReceived |= sr->sr_OwnerSigMask;
  1001.  
  1002.                                     WaitIO((struct IORequest *)timeRequest);
  1003.  
  1004.                                     /* Restart the timer. */
  1005.                                     timeRequest->tr_node.io_Command    = TR_ADDREQUEST;
  1006.                                     timeRequest->tr_time.tv_secs    = 0;
  1007.                                     timeRequest->tr_time.tv_micro    = MILLION / 10;
  1008.  
  1009.                                     SendIO((struct IORequest *)timeRequest);
  1010.                                 }
  1011.                             }
  1012.  
  1013.                             /* Check if we should test the buffer. */
  1014.                             if(signalsReceived & sr->sr_OwnerSigMask)
  1015.                             {
  1016.                                 if(NOT ShellArguments.Quiet)
  1017.                                 {
  1018.                                     UBYTE localBuffer[256];
  1019.                                     ULONG moreSignals;
  1020.                                     LONG filled;
  1021.  
  1022.                                     /* Try to empty the circular buffer. */
  1023.                                     while((filled = ReadFIFOChars(sr,localBuffer,sizeof(localBuffer))) > 0)
  1024.                                     {
  1025.                                         /* Check if there is a message for us. */
  1026.                                         moreSignals = SetSignal(0,SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F);
  1027.  
  1028.                                         /* Save the circular buffer to a file? */
  1029.                                         if(moreSignals & SIGBREAKF_CTRL_F)
  1030.                                         {
  1031.                                             LONG error;
  1032.  
  1033.                                             error = SaveBuffer(saveFile,sr,MODE_Regular);
  1034.                                             if(error == OK)
  1035.                                                 Printf("Sashimi buffer saved as \"%s\".\n",saveFile);
  1036.                                             else
  1037.                                                 PrintFault(error,saveFile);
  1038.                                         }
  1039.  
  1040.                                         /* Empty the circular buffer? */
  1041.                                         if(moreSignals & SIGBREAKF_CTRL_E)
  1042.                                         {
  1043.                                             EmptyFIFO(sr);
  1044.  
  1045.                                             Printf("Sashimi buffer cleared.\n");
  1046.                                             filled = 0;
  1047.                                         }
  1048.  
  1049.                                         /* Stop Sashimi? */
  1050.                                         if(moreSignals & SIGBREAKF_CTRL_C)
  1051.                                         {
  1052.                                             signalsReceived |= SIGBREAKF_CTRL_C;
  1053.                                             break;
  1054.                                         }
  1055.  
  1056.                                         /* Write the buffer to the file. */
  1057.                                         if(filled > 0)
  1058.                                             Write(Output(),localBuffer,filled);
  1059.                                     }
  1060.                                 }
  1061.                             }
  1062.  
  1063.                             /* Check if we should return from Quiet mode. */
  1064.                             if(signalsReceived & sr->sr_WakeSigMask)
  1065.                             {
  1066.                                 if(ShellArguments.Quiet)
  1067.                                 {
  1068.                                     ULONG moreSignals;
  1069.                                     STRPTR buffer;
  1070.  
  1071.                                     /* Return from quiet mode. */
  1072.                                     ShellArguments.Quiet = FALSE;
  1073.  
  1074.                                     /* We allocate a temporary buffer to store the circular
  1075.                                      * buffer data in.
  1076.                                      */
  1077.                                     buffer = AllocVec(sr->sr_FIFOTotalSize,MEMF_ANY|MEMF_PUBLIC);
  1078.                                     if(buffer != NULL)
  1079.                                     {
  1080.                                         LONG bytes_in_buffer;
  1081.                                         BOOL wrapped;
  1082.                                         BOOL overrun;
  1083.                                         UBYTE * mem;
  1084.                                         LONG i,len;
  1085.  
  1086.                                         Disable();
  1087.  
  1088.                                         wrapped = sr->sr_FIFOWrapped;
  1089.                                         overrun = sr->sr_FIFOOverrun;
  1090.  
  1091.                                         if(wrapped)
  1092.                                         {
  1093.                                             LONG oldBytes = sr->sr_FIFOTotalSize - sr->sr_FIFOWriteIndex;
  1094.  
  1095.                                             /* Unwrap the buffer; first copy the old data (following the
  1096.                                              * write index) then the newer data.
  1097.                                              */
  1098.                                             memcpy(buffer,&sr->sr_FIFO[sr->sr_FIFOWriteIndex],oldBytes);
  1099.                                             memcpy(&buffer[oldBytes],sr->sr_FIFO,sr->sr_FIFOWriteIndex);
  1100.  
  1101.                                             bytes_in_buffer = sr->sr_FIFOTotalSize;
  1102.                                         }
  1103.                                         else
  1104.                                         {
  1105.                                             memcpy(buffer,sr->sr_FIFO,sr->sr_FIFOWriteIndex);
  1106.  
  1107.                                             bytes_in_buffer = sr->sr_FIFOWriteIndex;
  1108.                                         }
  1109.  
  1110.                                         /* Start interrupts and multitasking again. */
  1111.                                         Enable();
  1112.  
  1113.                                         /* Write the buffer contents. */
  1114.                                         if(overrun)
  1115.                                             Printf("BUFFER WAS OVERRUN - Data may have been lost\n");
  1116.  
  1117.                                         if(wrapped)
  1118.                                             Printf("BUFFER WRAPPED - This is the most recent captured data\n\n");
  1119.  
  1120.                                         mem = buffer;
  1121.                                         while(bytes_in_buffer > 0)
  1122.                                         {
  1123.                                             /* Check if there is a message for us. */
  1124.                                             moreSignals = SetSignal(0,SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F);
  1125.  
  1126.                                             /* Save the circular buffer to a file? */
  1127.                                             if(moreSignals & SIGBREAKF_CTRL_F)
  1128.                                             {
  1129.                                                 LONG error;
  1130.  
  1131.                                                 error = SaveBuffer(saveFile,sr,MODE_Regular);
  1132.                                                 if(error == OK)
  1133.                                                     Printf("Sashimi buffer saved as \"%s\".\n",saveFile);
  1134.                                                 else
  1135.                                                     PrintFault(error,saveFile);
  1136.                                             }
  1137.  
  1138.                                             /* Empty the circular buffer? */
  1139.                                             if(moreSignals & SIGBREAKF_CTRL_E)
  1140.                                             {
  1141.                                                 EmptyFIFO(sr);
  1142.  
  1143.                                                 Printf("Sashimi buffer cleared.\n");
  1144.                                                 bytes_in_buffer = 0;
  1145.                                             }
  1146.  
  1147.                                             /* Stop Sashimi? */
  1148.                                             if(moreSignals & SIGBREAKF_CTRL_C)
  1149.                                             {
  1150.                                                 signalsReceived |= SIGBREAKF_CTRL_C;
  1151.                                                 break;
  1152.                                             }
  1153.  
  1154.                                             len = bytes_in_buffer;
  1155.                                             for(i = 0 ; i < bytes_in_buffer ; i++)
  1156.                                             {
  1157.                                                 if(mem[i] < ' ' && mem[i] != '\t')
  1158.                                                 {
  1159.                                                     len = i+1;
  1160.                                                     break;
  1161.                                                 }
  1162.                                             }
  1163.  
  1164.                                             if(len > 0)
  1165.                                             {
  1166.                                                 FWrite(Output(),mem,len,1);
  1167.  
  1168.                                                 mem += len;
  1169.                                                 bytes_in_buffer -= len;
  1170.                                             }
  1171.                                         }
  1172.  
  1173.                                         Flush(Output());
  1174.  
  1175.                                         FreeVec(buffer);
  1176.                                     }
  1177.                                     else
  1178.                                     {
  1179.                                         Printf("Not enough memory to make a copy of the FIFO contents.\n");
  1180.                                     }
  1181.                                 }
  1182.                             }
  1183.  
  1184.                             /* Save current buffer to file. */
  1185.                             if(signalsReceived & SIGBREAKF_CTRL_F)
  1186.                             {
  1187.                                 LONG error;
  1188.  
  1189.                                 error = SaveBuffer(saveFile,sr,MODE_Regular);
  1190.                                 if(error == OK)
  1191.                                     Printf("Sashimi buffer saved as \"%s\".\n",saveFile);
  1192.                                 else
  1193.                                     PrintFault(error,saveFile);
  1194.                             }
  1195.  
  1196.                             /* Empty the buffer. */
  1197.                             if(signalsReceived & SIGBREAKF_CTRL_E)
  1198.                             {
  1199.                                 EmptyFIFO(sr);
  1200.  
  1201.                                 Printf("Sashimi buffer cleared.\n");
  1202.                             }
  1203.  
  1204.                             /* Reset the terminal. */
  1205.                             if(signalsReceived & SIGBREAKF_CTRL_D)
  1206.                             {
  1207.                                 Printf("\033c");
  1208.                                 Flush(Output());
  1209.                             }
  1210.  
  1211.                             /* Terminate the program. */
  1212.                             if(signalsReceived & SIGBREAKF_CTRL_C)
  1213.                             {
  1214.                                 BOOL terminate = FALSE;
  1215.  
  1216.                                 if(ShellArguments.AskExit)
  1217.                                 {
  1218.                                     UBYTE buffer[4];
  1219.  
  1220.                                     Printf("\nSashimi: stop signal received -- really exit (y or n)? ");
  1221.                                     Flush(Output());
  1222.  
  1223.                                     buffer[0] = '\0';
  1224.  
  1225.                                     if(FGets(Input(),buffer,sizeof(buffer)-1) != NULL)
  1226.                                     {
  1227.                                         if(buffer[0] == 'y' || buffer[0] == 'Y')
  1228.                                             terminate = TRUE;
  1229.                                     }
  1230.                                 }
  1231.                                 else
  1232.                                 {
  1233.                                     terminate = TRUE;
  1234.                                 }
  1235.  
  1236.                                 if(terminate)
  1237.                                 {
  1238.                                     if(RemoveSashimiResource(sr) == OK)
  1239.                                     {
  1240.                                         Printf("Sashimi removed.\n");
  1241.                                         done = TRUE;
  1242.                                     }
  1243.                                 }
  1244.                             }
  1245.                         }
  1246.                         while(NOT done);
  1247.  
  1248.                         RemovePatches();
  1249.  
  1250.                         /* Stop the timer. */
  1251.                         if(ShellArguments.TimerOn)
  1252.                         {
  1253.                             if(CheckIO((struct IORequest *)timeRequest) == BUSY)
  1254.                                 AbortIO((struct IORequest *)timeRequest);
  1255.  
  1256.                             WaitIO((struct IORequest *)timeRequest);
  1257.                         }
  1258.  
  1259.                         /* Check if we should and could save the circular buffer. */
  1260.                         if(ShellArguments.AskSave && GetCharsInFIFO(sr) > 0)
  1261.                         {
  1262.                             UBYTE name[256];
  1263.  
  1264.                             Printf("Enter name to save the buffer, or hit [Return] to cancel: ");
  1265.                             Flush(Output());
  1266.  
  1267.                             name[0] = '\0';
  1268.  
  1269.                             if(FGets(Input(),name,sizeof(name)-1) != NULL)
  1270.                             {
  1271.                                 LONG error;
  1272.                                 int i;
  1273.  
  1274.                                 for(i = strlen(name)-1 ; i >= 0 ; i--)
  1275.                                 {
  1276.                                     if(name[i] == '\n')
  1277.                                         name[i] = '\0';
  1278.                                 }
  1279.  
  1280.                                 error = SaveBuffer(name,sr,MODE_Regular);
  1281.                                 if(error == OK)
  1282.                                     Printf("Sashimi buffer saved as \"%s\".\n",name);
  1283.                                 else
  1284.                                     PrintFault(error,name);
  1285.                             }
  1286.                         }
  1287.  
  1288.                         FreeSashimiResource(sr);
  1289.                         sr = NULL;
  1290.                     }
  1291.  
  1292.                     result = RETURN_OK;
  1293.                 }
  1294.  
  1295.                 /* Close the resource, if we opened it. */
  1296.                 if(opened)
  1297.                     CloseSashimiResource(sr);
  1298.  
  1299.                 /* Remove and free the resource if we added it. */
  1300.                 if(added)
  1301.                 {
  1302.                     RemoveSashimiResource(sr);
  1303.                     FreeSashimiResource(sr);
  1304.                 }
  1305.  
  1306.                 /* Clean up the timer.device interface. */
  1307.                 if(timeRequest != NULL)
  1308.                 {
  1309.                     if(timeRequest->tr_node.io_Device != NULL)
  1310.                         CloseDevice((struct IORequest *)timeRequest);
  1311.  
  1312.                     DeleteIORequest((struct IORequest *)timeRequest);
  1313.                 }
  1314.  
  1315.                 DeleteMsgPort(timePort);
  1316.  
  1317.                 /* Reset and clean up the console I/O streams. */
  1318.                 if(oldOutput != ZERO)
  1319.                     SelectOutput(oldOutput);
  1320.  
  1321.                 if(oldInput != ZERO)
  1322.                     SelectInput(oldInput);
  1323.  
  1324.                 if(newOutput != ZERO)
  1325.                     Close(newOutput);
  1326.  
  1327.                 if(oldConsoleTask != NULL)
  1328.                     SetConsoleTask(oldConsoleTask);
  1329.  
  1330.                 if(newInput != ZERO)
  1331.                     Close(newInput);
  1332.             }
  1333.  
  1334.             FreeArgs(rdargs);
  1335.         }
  1336.         else
  1337.         {
  1338.             PrintFault(IoErr(),"Sashimi");
  1339.  
  1340.             result = RETURN_ERROR;
  1341.         }
  1342.     }
  1343.  
  1344.     return(result);
  1345. }
  1346.